#ifndef INCLUDE_OS_SAFE_PTR
#define INCLUDE_OS_SAFE_PTR

#include <stdlib.h>
#define OUT_OF_BOUNDS_EXCEPTION 100
#define NOT_ENOUGH_SPACE_EXCEPTION 101

#define SafePtrLibraryNewDeleteMacro(C)\
void* operator new(size_t size) throw() {\
    if (size > 0) {\
		if (globalPool == NULL) {\
			globalPool = new pool();\
		}\
        void* ans = globalPool->requestMem(size);\
		if (ans == 0) {\
			throw NOT_ENOUGH_SPACE_EXCEPTION;\
		}\
        return ans;\
     }\
     else {\
        return NULL;\
	}\
}\
void* operator new[](size_t size) throw() {\
    if (size > 0) {\
		if (globalPool == NULL) {\
			globalPool = new pool();\
		}\
        void* ans = globalPool->requestMem(size);\
		if (ans == 0) {\
			throw NOT_ENOUGH_SPACE_EXCEPTION;\
		}\
        return ans;\
     }\
     else {\
        return NULL;\
	}\
}\



pool *globalPool; // This is the global pool from which we can request memory

template <class T>
class SafePtr {
	T * m;
	public:
	SafePtr(T *p = NULL) { 
        m = p; 
    }
	~SafePtr() {
		if (m != NULL) {
			globalPool->deleteMem((void*)m);
			cout << "\\= Object destroyed =/" << endl;
			//if list empty, delete the mem allocated for pool
			if (globalPool->empty()) {
				delete(globalPool);
                globalPool = NULL;
				cout << "\\= Pool destroyed =/" << endl;
			}
		}
	}

	//copy constructor source: http://ootips.org/yonat/4dev/copied_ptr.h
    SafePtr(const SafePtr& r) { copy(r.m); }
    SafePtr& operator=(const SafePtr& r) {

        if (this != &r) {

            delete m;

            copy(r);

        }

        return *this;

    }
	operator const void*() const{return m ? this : 0;}

    void copy(const SafePtr& r) {
		m = r.m ? new T(*r.m) : 0;
	}
	//ends here


	T* operator->() { return m; }
	T& operator*() { return *m; }
	T& operator[](unsigned int t) {
		if (t*sizeof(T) < globalPool->length((void*)m)) {
			return *(m+t*sizeof(T));
		}
		throw OUT_OF_BOUNDS_EXCEPTION;
	}
};


#endif
